package com.nineclock.auth.intergration.aop;

import com.nineclock.auth.intergration.entity.IntergrationAuthenticationEntity;
import com.nineclock.auth.intergration.entity.NcOauthTokenDTO;
import com.nineclock.auth.intergration.threadLocal.IntergrationAuthenticationHolder;
import com.nineclock.auth.intergration.threadLocal.UserHolder;
import com.nineclock.common.entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class AuthTokenAspect {


    /**
     * 环绕通知
     * @return
     */
    @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public Object postHandleAuthTokenResult(ProceedingJoinPoint joinPoint){

        log.info("AOP认证拦截");

        Object returnObj = null;

        Result<NcOauthTokenDTO> result = null;

        try {
            // 1.获取到request对象
            HttpServletRequest request = ((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();

            // 2.获取请求参数
            String authType = request.getParameter("auth_type");
            IntergrationAuthenticationEntity entity = new IntergrationAuthenticationEntity();
            entity.setAuthType(authType);
            // 获取其他参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            entity.setAuthParameters(parameterMap);

            // 3.通过ThreadLocal传递参数到UserDetailServiceImpl
            // 将entity对象放到当前线程内
            IntergrationAuthenticationHolder.set(entity);

            // 4.执行目标方法
            returnObj = joinPoint.proceed();

            if (returnObj != null) {

                // 获取原始方法返回结果
                ResponseEntity<OAuth2AccessToken> responseEntity = (ResponseEntity<OAuth2AccessToken>) returnObj;

                // 获取原始方法结果中的响应体
                OAuth2AccessToken oAuth2AccessToken = responseEntity.getBody();

                // 封装返回结果
                NcOauthTokenDTO ncOauthTokenDTO = new NcOauthTokenDTO();
                ncOauthTokenDTO.setOauth2AccessToken(oAuth2AccessToken);
                ncOauthTokenDTO.setUser(UserHolder.get());

                result = Result.success(ncOauthTokenDTO);
            }


        } catch (Throwable throwable) {

            log.error("拦截认证请求出错：", throwable);

            result = Result.errorCodeMessage(401, throwable.getMessage());

            return ResponseEntity.status(result.getCode()).body(result);

        } finally {
            // 移除threadLocal线程本地变量
            IntergrationAuthenticationHolder.remove();
            UserHolder.remove();

        }

        return ResponseEntity.ok(result);
    }
}
